#include <linux/module.h>
#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>

MODULE_LICENSE("GPL");

#define LED1 74

static struct cdev* ledCdev;
static dev_t devt;

int led_open(struct inode *inode, struct file *filp)
{
	return 0;
}
int led_release(struct inode *inode, struct file *filp)
{
	return 0;
}
ssize_t led_write(struct file *filp, const char __user *buf, size_t len, loff_t *offset)
{
	int cmd = 0;
	
	if(copy_from_user(&cmd, buf,  len))
    {
		printk("copy failed\n");
		return -EFAULT;
	}

	//gpio_set_value(LED1, *buf); //*buf, 直接读用户空间内存 不允许
	gpio_set_value(LED1, cmd);

	return len;

}
ssize_t led_read(struct file *filp, char __user *buf, size_t len, loff_t *offset)
{
	int stat = 0;
	stat = gpio_get_value(LED1);

	//*buf = stat; //直接写用户空间内存， 不允许
	if(copy_to_user(buf, &stat, len))
    {
		printk("copy failed!\n");
		return -EFAULT;
	}

	return len;

}

static struct file_operations ledFops = 
{
    .owner = THIS_MODULE,
	.open = led_open,
	.release = led_release,
    .write = led_write,
	.read = led_read
};

static int __init led_drv_init(void)
{
	alloc_chrdev_region(&devt, 0, 1, "led1");
	ledCdev = cdev_alloc();
	cdev_init(ledCdev,&ledFops);
	cdev_add(ledCdev,devt,1);

	if(gpio_request(LED1,"led1"))
	{
		printk("gpio_request failed\n");
		return -EINVAL;
	}

	gpio_direction_output(LED1,0);
	return 0;
}

static void __exit led_drv_exit(void)
{
	gpio_free(LED1);
	cdev_del(ledCdev);
}

module_init(led_drv_init);
module_exit(led_drv_exit);